#include "login_register_client.h"

int join_with_spaces(char *dest, size_t dest_size,
                     const char *str1, const char *str2, const char *str3,
                     int space_count)
{
    // 计算所需空间
    size_t needed = strlen(str1) + strlen(str2) + strlen(str3) + (space_count * 2) + 1;
    if (dest_size < needed)
    {
        return -1; // 缓冲区不足
    }
    // 清空目标缓冲区
    memset(dest, 0, dest_size);
    // 复制第一个字符串
    strcat(dest, str1);
    // 添加空格
    for (int i = 0; i < space_count; i++)
    {
        strcat(dest, " ");
    }
    // 添加第二个字符串
    strcat(dest, str2);
    // 添加空格
    for (int i = 0; i < space_count; i++)
    {
        strcat(dest, " ");
    }
    // 添加第三个字符串
    strcat(dest, str3);
    return 0;
}

// 注册函数
int register_user(ClientContext *ctx, UserLogInfo *user)
{
    if (!ctx || !user || !user->user_name || !user->password)
    {
        fprintf(stderr, "[ERROR] 无效参数\n");
        return -1;
    }

    CommandType_e cmd;
    char salt[45] = {0};
    int ret;

    // 第一阶段：发送注册请求
    cmd = CMD_REGISTER_APPLY;
    if ((ret = send_command(ctx, cmd, NULL, 0)) != 0) // 发送空请求
    {
        fprintf(stderr, "[ERROR] 发送注册请求失败: %d\n", ret);
        ctx->state = STATE_ERROR;
        return ret;
    }
    ctx->state = STATE_AWAIT_AUTH;

    protocol_header_t header;
    // 接收盐值
    if ((ret = receive_response(ctx, &header, salt, sizeof(salt))) != 0)
    {
        fprintf(stderr, "[ERROR] 接收盐值失败: %d\n", ret);
        ctx->state = STATE_ERROR;
        return ret;
    }

    if (header.resp_type != SUCESS)
    {
        fprintf(stderr, "[ERROR] 服务端发送盐值过程失败\n");
        ctx->state = STATE_ERROR;
        return -1;
    }
    else if (header.command != CMD_REGISTER_APPLY)
    {
        fprintf(stderr, "[ERROR] 意外命令: %d\n", header.command);
        ctx->state = STATE_ERROR;
        return -1;
    }

    // 加密密码
    char *encrypted_pass = crypt(user->password, salt);
    if (encrypted_pass == NULL)
    {
        fprintf(stderr, "[ERROR] 密码加密失败\n");
        ctx->state = STATE_ERROR;
        return -1;
    }

    // 准备组合数据：用户名 + 5空格 + 加密密码 + 5空格 + 盐值
    char combined_data[256] = {0}; // 适当大小的缓冲区
    if (join_with_spaces(combined_data, sizeof(combined_data),
                         user->user_name, encrypted_pass, salt, 5) != 0)
    {
        fprintf(stderr, "[ERROR] 数据合并失败了\n");
        ctx->state = STATE_ERROR;
        return -1;
    }

    // 第二阶段：发送组合数据
    cmd = CMD_REGISTER;
    if ((ret = send_command(ctx, cmd, combined_data, strlen(combined_data))) != 0)
    {
        fprintf(stderr, "[ERROR] 发送注册数据失败: %d\n", ret);
        ctx->state = STATE_ERROR;
        return ret;
    }

    // 接收最终注册结果
    char result_buf[1024] = {0};
    if ((ret = receive_response(ctx, &header, result_buf, sizeof(result_buf))) != 0)
    {
        fprintf(stderr, "[ERROR] 接收注册结果失败: %d\n", ret);
        ctx->state = STATE_ERROR;
        return ret;
    }

    if (header.command == ERR_USER_EXISTS)
    {
        printf("用户名已存在!\n");
        return -1;
    }

    if (header.command == CMD_REGISTER && header.resp_type == SUCESS)
    {
        printf("恭喜，注册成功！\n");
        ctx->state = STATE_REGISTER;
        return 0;
    }
    else if (header.command == CMD_REGISTER && header.resp_type == FAIL)
    {
        fprintf(stderr, "[ERROR] 注册失败: %s\n", result_buf);
        ctx->state = STATE_REGISTER_FAIL;
        return -1;
    }
    else
    {
        fprintf(stderr, "[ERROR] 意外响应: %d\n", header.command);
        ctx->state = STATE_REGISTER_FAIL;
        return -1;
    }
}

// 登录函数
int login_user(ClientContext *ctx, UserLogInfo *user)
{
    if (!ctx || !user || !user->user_name || !user->password)
    {
        fprintf(stderr, "[ERROR] 无效参数\n");
        return -1;
    }

    CommandType_e cmd;
    char salt[45] = {0};
    int ret;
    ctx->state = STATE_AWAIT_AUTH;
    // 第一阶段：发送带有用户名的登录请求
    cmd = CMD_LOGIN_APPLY;
    if ((ret = send_command(ctx, cmd, user->user_name, strlen(user->user_name))) != 0) // 发送空请求
    {
        fprintf(stderr, "[ERROR] 发送登录请求失败: %d\n", ret);
        ctx->state = STATE_LOGIN_FAIL;
        return ret;
    }

    protocol_header_t header;
    // 接收盐值
    if ((ret = receive_response(ctx, &header, salt, sizeof(salt))) != 0)
    {
        fprintf(stderr, "[ERROR] 接收盐值失败: %d\n", ret);
        ctx->state = STATE_LOGIN_FAIL;
        return ret;
    }

    if (header.command == CMD_LOGIN_APPLY && header.resp_type == FAIL)
    {
        fprintf(stderr, "用户名或密码输入错误\n");
        ctx->state = STATE_LOGIN_FAIL;
        return -1;
    }

    // 加密密码
    char *encrypted_pass = crypt(user->password, salt);
    if (encrypted_pass == NULL)
    {
        fprintf(stderr, "[ERROR] 密码加密失败\n");
        ctx->state = STATE_LOGIN_FAIL;
        return -1;
    }

    // 准备组合数据：用户名 + 5空格 + 加密密码 + 5空格 + 盐值
    char combined_data[256] = {0}; // 适当大小的缓冲区
    if (join_with_spaces(combined_data, sizeof(combined_data),
                         user->user_name, encrypted_pass, salt, 5) != 0)
    {
        fprintf(stderr, "[ERROR] 数据合并失败了\n");
        ctx->state = STATE_LOGIN_FAIL;
        return -1;
    }

    // 第二阶段：发送组合数据
    cmd = CMD_LOGIN;
    if ((ret = send_command(ctx, cmd, combined_data, strlen(combined_data))) != 0)
    {
        fprintf(stderr, "[ERROR] 发送登录数据失败: %d\n", ret);
        ctx->state = STATE_LOGIN_FAIL;
        return ret;
    }

    // 接收最终登录结果
    char result_buf[1024] = {0};
    if ((ret = receive_response(ctx, &header, result_buf, sizeof(result_buf))) != 0)
    {
        fprintf(stderr, "[ERROR] 接收登录结果失败: %d\n", ret);
        ctx->state = STATE_LOGIN_FAIL;
        return ret;
    }

    if (header.command == CMD_LOGIN && header.resp_type == SUCESS)
    {
        printf("恭喜，登录成功！\n");
        ctx->state = STATE_LOGIN;
        // 保存Token到上下文
        strncpy(ctx->token, result_buf, sizeof(ctx->token));
        printf("登陆成功接收的token:%s\n", ctx->token);
        return 0;
    }
    else if (header.command == CMD_LOGIN && header.resp_type == FAIL)
    {
        fprintf(stderr, "[ERROR] 登录失败: %s\n", result_buf);
        ctx->state = STATE_LOGIN_FAIL;
        return -1;
    }
    else
    {
        fprintf(stderr, "[ERROR] 意外响应: %d\n", header.command);
        ctx->state = STATE_LOGIN_FAIL;
        return -1;
    }
}